#pragma once

#include "OrionFlames.h"
#include "Preset.h"

namespace OrionFlames
{
//EXPORT_STL_VECTOR(OFAPI, Preset*)

class StandardBenchmark : public Preset
{
public:
	StandardBenchmark() : Preset("Standard Benchmark", 0.1, 66, 1.5, 0.6, 0.25)
	{
		xForm hyperbolic;
		hyperbolic.Tag("0");
		hyperbolic.Weight(0.377f);
		hyperbolic.X(vec2(-0.360294, -0.439868));
		hyperbolic.Y(vec2(0.94579, -0.861994));
		hyperbolic.O(vec2(1.120671, -1.359398));
		hyperbolic.NonlinearWeight(1.0);
		hyperbolic.Var(VariationList::LookupVariation("hyperbolic"));

		xForm linear;
		linear.Tag("1");
		linear.Weight(0.298f);
		linear.X(vec2(0.871566, 0.250037));
		linear.Y(vec2(0.467305, 0.979817));
		linear.O(vec2(-0.990552, -0.538029));
		linear.NonlinearWeight(1);
		//xf.wvar=0.8; 
		linear.Var(VariationList::LookupVariation("linear"));

		xForm hyperbolic2;
		hyperbolic2.Tag("2");
		hyperbolic2.Weight(0.325f);
		hyperbolic2.X(vec2(-0.326387, 0.395477));
		hyperbolic2.Y(vec2(-0.415395, -0.380892));
		hyperbolic2.O(vec2(-0.782861, -1.30803));
		hyperbolic2.NonlinearWeight(1.0f);
		hyperbolic2.Var(VariationList::LookupVariation("hyperbolic")); // ex; //<- has no inverse
		
		m_Transforms.push_back(hyperbolic);
		m_Transforms.push_back(linear);
		m_Transforms.push_back(hyperbolic2);
	}
};

class Caberet : public Preset
{
public:
	Caberet() : Preset("Caberet", 0.4, 66, -1.6, 0.55, 0.25)
	{
		xForm polar;
		polar.Tag("0");
		polar.Weight(0.4f);
		polar.X(vec2(1, -1));
		polar.Y(vec2(0.5, 0.5));
		polar.O(vec2(-0.3, -2.1));
		polar.NonlinearWeight(1.0f);
		polar.Var(VariationList::LookupVariation("polar"));

		xForm linear;
		linear.Tag("1");
		linear.Weight(0.3f);
		linear.X(vec2(1, 0));
		linear.Y(vec2(0, 1));
		linear.O(vec2(-1.2, -0.9));
		linear.NonlinearWeight(1.0f);
		//xf.wvar=0.8; 
		linear.Var(VariationList::LookupVariation("linear"));

		xForm spherical;
		spherical.Tag("2");
		spherical.Weight(0.4f);
		spherical.X(vec2(-0.2, 0.4));
		spherical.Y(vec2(-0.4, -0.3));
		spherical.O(vec2(-1.0, -1.3));
		spherical.NonlinearWeight(1.65f);
		spherical.Var(VariationList::LookupVariation("spherical"));

		m_Transforms.push_back(polar);
		m_Transforms.push_back(linear);
		m_Transforms.push_back(spherical);
	}
};

class Fountains : public Preset
{
public:
	Fountains() : Preset("Fountains", 0.4, 66, -1.6, 0.55, 0.25)
	{
		xForm polar;
		polar.Tag("0");
		polar.Weight(0.4f);
		polar.X(vec2(1, -1));
		polar.Y(vec2(0.5, 0.5));
		polar.O(vec2(0.6, -3.0));
		polar.NonlinearWeight(1.0f);
		polar.Var(VariationList::LookupVariation("polar"));
		
		xForm linear;
		linear.Tag("1");
		linear.Weight(0.3f);
		linear.X(vec2(1, 0));
		linear.Y(vec2(0, 1));
		linear.O(vec2(-1.995, -0.0));
		linear.NonlinearWeight(1.0f);
		//xf.wvar=0.8; 
		linear.Var(VariationList::LookupVariation("linear"));

		xForm spherical;
		spherical.Tag("2");
		spherical.Weight(0.3f);
		spherical.X(vec2(-0.2, 0.4));
		spherical.Y(vec2(-0.4, -0.3));
		spherical.O(vec2(-1.0, -1.3));
		spherical.NonlinearWeight(1.8f);
		spherical.Var(VariationList::LookupVariation("spherical"));

		m_Transforms.push_back(polar);
		m_Transforms.push_back(linear);
		m_Transforms.push_back(spherical);
	}
};

class TwoMapSpiral : public Preset
{
public:
	TwoMapSpiral() : Preset("Two Map Spiral", 0.1, 66, -1.5, 0.3, 0.25)
	{
		xForm hyperbolic;
		hyperbolic.Tag("0");
		hyperbolic.Weight(0.5f);
		hyperbolic.X(vec2(1, 0));
		hyperbolic.Y(vec2(0, 1));
		hyperbolic.O(vec2(0, 0));
		hyperbolic.NonlinearWeight(1.0f);
		hyperbolic.Var(VariationList::LookupVariation("hyperbolic"));
		
		xForm linear;
		linear.Tag("1");
		linear.Weight(0.5f);
		linear.X(vec2(0.8, 0.4));
		linear.Y(vec2(-0.4, 0.8));
		linear.O(vec2(-1, 0.3));
		//linear.wvar=1;
		linear.NonlinearWeight(1.0f); 
		linear.Var(VariationList::LookupVariation("linear"));

		m_Transforms.push_back(hyperbolic);
		m_Transforms.push_back(linear);
	}
};

class Eyes : public Preset
{
public:
	Eyes() : Preset("Eyes", 0.1, 66, -1.5, 0.3, 0.25)
	{
		xForm fisheye;
		fisheye.Tag("0");
		fisheye.Weight(0.5);
		fisheye.X(vec2(1, 0));
		fisheye.Y(vec2(0, 1));
		fisheye.O(vec2(0, 0));
		fisheye.NonlinearWeight(0.5);
		fisheye.Var(VariationList::LookupVariation("fisheye"));

		xForm linear;
		linear.Tag("1");
		linear.Weight(0.4f);
		linear.X(vec2(0.8, 0.4));
		linear.Y(vec2(-0.4, 0.8));
		linear.O(vec2(-1, 0.3));
		linear.NonlinearWeight(1.0f);
		linear.Var(VariationList::LookupVariation("linear"));

		xForm hyperbolic;
		hyperbolic.Tag("2");
		hyperbolic.Weight(0.1f);
		hyperbolic.X(vec2(1, 1));
		hyperbolic.Y(vec2(-1, 1));
		hyperbolic.O(vec2(0, 0));
		hyperbolic.NonlinearWeight(3.2f);
		hyperbolic.Var(VariationList::LookupVariation("hyperbolic"));

		m_Transforms.push_back(fisheye);
		m_Transforms.push_back(linear);
		m_Transforms.push_back(hyperbolic);
	}
};

class Swirlpinski : public Preset
{
public:
	Swirlpinski() : Preset("Swirlpinski", 1.0, 2.0, 1.8, 0.5, 0.25)
	{
		float scale = 1.3f;//Controls amount of nonlinearity experienced.

		m_FirstLevel = 8;
		m_LastLevel = 11;//Swirl hits mipmap troubles at low res.
		m_Iterations = 5;

		xForm swirl;
		swirl.Tag("0");
		swirl.Weight(0.333f);
		swirl.X(vec2(0, 0.5));
		swirl.Y(vec2(0.5, 0));
		//swirl.X(vec2(0.5, 0);
		//swirl.Y(vec2(0, 0.5);
		swirl.O(vec2(0, 0));
		swirl.NonlinearWeight(1.0f);
		swirl.Var(VariationList::LookupVariation("swirl"));

		xForm linear;
		linear.Tag("1");
		linear.Weight(0.333f);
		linear.X(vec2(0.5, 0));
		linear.Y(vec2(0, 0.5));
		linear.O(vec2(+scale, 0));
		linear.NonlinearWeight(1.0f);
		linear.Var(VariationList::LookupVariation("linear"));

		xForm linear2;
		linear2.Tag("2");
		linear2.Weight(0.333f);
		linear2.X(vec2(0.5, 0));
		linear2.Y(vec2(0, 0.5));
		linear2.O(vec2(0.3 * scale, -scale));
		linear2.NonlinearWeight(1.0f);
		linear2.Var(VariationList::LookupVariation("linear"));

		m_Transforms.push_back(swirl);
		m_Transforms.push_back(linear);
		m_Transforms.push_back(linear2);
	}
};

class UnboundedAffine : public Preset
{
public:
	UnboundedAffine() : Preset("Unbounded Affine", 1.0, 1.0, 1.35, 0.0, 0.82)
	{
		xForm linear;
		linear.Tag("0");
		linear.Weight(0.5f);
		linear.X(vec2(1.5, 0));
		linear.Y(vec2(0, 0.2));
		linear.O(vec2(0.25, -0.4));
		linear.NonlinearWeight(1.0f);
		linear.Var(VariationList::LookupVariation("linear"));
		
		xForm linear2;
		linear2.Tag("1");
		linear2.Weight(0.5f);
		linear2.X(vec2(0, 0.8));
		linear2.Y(vec2(0.8, 0.0));
		linear2.O(vec2(0, 0));
		linear2.NonlinearWeight(1.0f);
		linear2.Var(VariationList::LookupVariation("linear"));

		m_Transforms.push_back(linear);
		m_Transforms.push_back(linear2);
	}
};

class BadVertex : public Preset
{
public:
	BadVertex() : Preset("Bad Vertex", 0.1, 66, -1.0, 0.4, 0.5)
	{
		xForm hyperbolic;
		hyperbolic.Tag("0");
		hyperbolic.Weight(0.33f);
		hyperbolic.X(vec2(-0.1, 1));
		hyperbolic.Y(vec2(1, 0.1));
		hyperbolic.O(vec2(0.32, -1));
		hyperbolic.NonlinearWeight(1.0f);
		hyperbolic.Var(VariationList::LookupVariation("hyperbolic"));

		xForm sinusoidal;
		sinusoidal.Tag("1"); // "NOINV"
		sinusoidal.Weight(1.3f);
		sinusoidal.X(vec2(1, -0.3));
		sinusoidal.Y(vec2(0.3, 1));
		sinusoidal.O(vec2(0, 0));
		sinusoidal.NonlinearWeight(2.0f);
		sinusoidal.Var(VariationList::LookupVariation("sinusoidal"));

		m_Transforms.push_back(hyperbolic);
		m_Transforms.push_back(sinusoidal);
	}
};

//http://sheep.arces.net/generation-165/dead.cgi?id=48&detail=genome
//<flame time="0" palette="39" size="640 480" scale="240" oversample="3" filter="1" quality="800" batches="200" brightness="4" gamma="4" vibrancy="1" hue="0" url="www.hallucinaut.com" nick="Hallucinaut">
//<xform weight="0.333" color="0" spherical="0.4" coefs="0.5 0 0 0.5 -0.565889 0.399552"/>
//<xform weight="0.333" color="0.5" spherical="0.4" coefs="0.5 0 0 0.5 0.565721 0.406814"/>
//<xform weight="0.333" color="1" spherical="0.4" coefs="0.5 0 0 0.5 0.001788 -0.551252"/>
//</flame>
class DravesGen165Sheep48 : public Preset
{
public:
	DravesGen165Sheep48() : Preset("Draves Gen 165 Sheep 48", 0.1, 66, 2.0, 0.5, 0.5)
	{
		xForm spherical1, spherical2, spherical3;

		//Our rounded values:
		/*spherical1.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.5 0 0 0.5 -0.566 0.400", "0");
		spherical2.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.5 0 0 0.5 0.566 0.400", "1");
		spherical3.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.5 0 0 0.5 0.000 -0.551", "2");*/

		//Exact copy of xml flame file (doesn't seem to make a difference):
		spherical1.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.5 0 0 0.5 -0.565889 0.399552", "0");
		spherical2.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.5 0 0 0.5 0.565721 0.406814", "1");
		spherical3.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.5 0 0 0.5 0.001788 -0.551252", "2");

		//Modified values from Fractron (looks pretty cool with x and y rotating, and doesn't collapse on itself):
		//spherical1.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.3491335 0.4118246 0.4590145 -0.3771884 -0.6313733 0.3610561", "0");
		//spherical2.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.8936951 -0.03990009 -0.00895116 0.3716458 0.3796634 0.2858488", "1");
		//spherical3.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.9738027 0.1636537 0.03052924 0.6537209 0.05417716 -1.178864", "2");

		m_Transforms.push_back(spherical1);
		m_Transforms.push_back(spherical2);
		m_Transforms.push_back(spherical3);
	}
};

//http://sheep.arces.net/generation-165/dead.cgi?id=1099&detail=genome
//<flame time="0" palette="82" size="640 480" scale="240" oversample="3" filter="1" quality="800" batches="200" brightness="4" gamma="4" vibrancy="1" hue="0.81411" parents="48 539">
//<xform weight="0.333" color="0" spherical="0.4" coefs="0.5 0 0 0.5 -0.565889 0.399552"/>
//<xform weight="0.5" color="0.5" linear="1" coefs="0.768479 -0.24519 -0.487981 -0.287183 -0.0927215 0.356433"/>
//<xform weight="0.333" color="1" spherical="0.4" coefs="0.5 0 0 0.5 0.001788 -0.551252"/>
//</flame>
class DravesGen165Sheep1099 : public Preset
{
public:
	DravesGen165Sheep1099() : Preset("Draves Gen 165 Sheep 1099", 0.1, 66, 2.0, 0.5, 0.5)
	{
		xForm spherical1, spherical2, linear1;
		spherical1.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.5 0 0 0.5 -0.565889 0.399552", "0");
		linear1.Init(0.5f, VariationList::LookupVariation("linear"), 1.0f, "0.768479 -0.24519 -0.487981 -0.287183 -0.0927215 0.356433", "1");
		spherical2.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.5 0 0 0.5 0.001788 -0.551252", "2");

		m_Transforms.push_back(spherical1);
		m_Transforms.push_back(linear1);
		m_Transforms.push_back(spherical2);
	}
};

//http://sheep.arces.net/generation-165/dead.cgi?id=19069&detail=genome
//<flame time="0" palette="77" size="640 480" scale="240" oversample="3" filter="1" quality="1200" batches="200" brightness="4" gamma="4" vibrancy="1" hue="0.96" parents="18743">
//<symmetry kind="3"/>
//<xform weight="0.267" color="0" spherical="1" coefs="-0.499769 0 0 -0.499769 -0.00637 1"/>
//<xform weight="0.267" color="0.33" spherical="1" coefs="-0.499769 0 0 -0.499769 -0.866025 -0.5"/>
//<xform weight="0.267" color="0.67" spherical="1" coefs="-0.499769 0 0 -0.499769 0.866025 -0.5"/>
//</flame>
class DravesGen165Sheep19069 : public Preset
{
public:
	DravesGen165Sheep19069() : Preset("Draves Gen 165 Sheep 19069", 0.1, 66, 2.0, 0.67, 0.5)
	{
		xForm spherical1, spherical2, spherical3;
		spherical1.Init(0.267f, VariationList::LookupVariation("spherical"), 1.0f, "-0.499769 0 0 -0.499769 -0.00637 1", "0");
		spherical2.Init(0.267f, VariationList::LookupVariation("spherical"), 1.0f, "-0.499769 0 0 -0.499769 -0.866025 -0.5", "1");
		spherical3.Init(0.267f, VariationList::LookupVariation("spherical"), 1.0f, "-0.499769 0 0 -0.499769 0.866025 -0.5", "2");

		m_Transforms.push_back(spherical1);
		m_Transforms.push_back(spherical2);
		m_Transforms.push_back(spherical3);
	}
};

//The Presets before this came with the original. The ones below are just experimental and are mostly bad.
class DravesTest : public Preset
{
public:
	DravesTest() : Preset("Draves Test", 0.1, 66, 2.0, 0.5, 0.5)
	{
		xForm xform1, xform2, xform3;
		xform1.Init(0.3333f, VariationList::LookupVariation("swirl"), 0.4f, "0.5 0 0 0.5 -0.566 0.400", "0");
		xform2.Init(0.3333f, VariationList::LookupVariation("spherical"), 0.4f, "0.5 0 0 0.5 0.566 0.400", "1");
		xform3.Init(0.3333f, VariationList::LookupVariation("power"), 0.4f, "0.5 0 0 0.5 0.000 -0.551", "2");

		m_Transforms.push_back(xform1);
		m_Transforms.push_back(xform2);
		m_Transforms.push_back(xform3);
	}
};

class JuliaCircle : public Preset
{
public:
	JuliaCircle() : Preset("Julia Circle", 0.1, 66, 2.0, 0.5, 0.5)
	{
		xForm xform1, xform2, xform3;
		xform1.Init(0.3333f, VariationList::LookupVariation("bent"), 0.4f, "0.5 0 0 0.5 -0.566 0.400", "0");
		//xform2.Init(0.3333f, VariationList::LookupVariation("fisheye"), 0.4f, "0.5 0 0 0.5 0.566 0.400", "1");
		//xform3.Init(0.3333f, VariationList::LookupVariation("power"), 0.4f, "0.5 0 0 0.5 0.000 -0.551", "2");

		//xform1.Init(0.508511f, VariationList::LookupVariation("julia"), 0.002f, "0.08212317 -0.04596011 0.04608798 0.08236153 0.500991 -0.132361", "0");
		//xform2.Init(1.0f, VariationList::LookupVariation("julia"), 1.0f, "-4.267016 -3.088871 3.088871 -4.267016 -0.00456566 -0.00589599", "1");
		//xform3.Init(0.03f, VariationList::LookupVariation("linear"), 1.0f, "-0.03835917 0.2055324 -0.2055324 -0.03835917 0.79491 -4.299344", "2");

		m_Transforms.push_back(xform1);
		//m_Transforms.push_back(xform2);
		//m_Transforms.push_back(xform3);
	}
};

class Sierpinski : public Preset
{
public:
	Sierpinski() : Preset("Sierpinski", 0.1, 66, 2.0, 0.5, 0.5)
	{
		xForm xform1, xform2, xform3;
		
		xform1.Init(0.333f, VariationList::LookupVariation("swirl"), 1.0f, "0.5 0 0 0.5 -0.433 0.25", "0");
		xform2.Init(0.333f, VariationList::LookupVariation("linear"), 1.0f, "0.5 0 0 0.5 0.433 0.25", "1");
		xform3.Init(0.333f, VariationList::LookupVariation("heart"), 1.0f, "0.5 0 0 0.5 0 -0.5", "2");

		m_Transforms.push_back(xform1);
		m_Transforms.push_back(xform2);
		m_Transforms.push_back(xform3);
	}
};

/*
<xform weight="1" color="1" f9k_color2="0.5" linear="1" coefs="0.3776757 0.2895004 -0.2895004 0.3776757 1.342276 0.3045362" />
<xform weight="0.333" color="0.25" f9k_color2="0.9" swirl="1" coefs="-0.1156983 -0.4362893 0.4362893 -0.1156983 -2.695997 -0.4008664" />
<xform weight="1" color="0.25" f9k_color2="0.1" popcorn="1" coefs="-0.1075431 -0.966361 0.966361 -0.1075431 -1.141692 -0.1890927" />
*/
//class F9K1 : public Preset
//{
//public:
//	F9K1() : Preset(0.1, 66, 2.0, 0.5, 0.5)
//	{
//		xForm linear, swirl, bent;
//		linear.Init(1.0f,   VariationList::LookupVariation("linear"), 1.0f, "0.3776757 0.2895004 -0.2895004 0.3776757 1.342276 0.3045362", "0");
//		swirl.Init (0.333f, VariationList::LookupVariation("swirl"),  1.0f, "-0.1156983 -0.4362893 0.4362893 -0.1156983 -2.695997 -0.4008664", "1");
//		bent.Init  (1.0f,   VariationList::LookupVariation("julia"),   1.0f, "-0.1075431 -0.966361 0.966361 -0.1075431 -1.141692 -0.1890927", "2");
//
//		m_Transforms.push_back(linear);
//		m_Transforms.push_back(swirl);
//		m_Transforms.push_back(bent);
//	}
//};

//For now this class is a hard coded list. In the future, it will need to read a folder of preset xml files - Matt.
class OFAPI PresetList
{
public:
	PresetList()
	{
		ClearPresets();//Should just guard with a bool rather than clear each time - Matt.
		//m_PresetVector.push_back(new DravesTest());
		m_PresetVector.push_back(new StandardBenchmark());
		m_PresetVector.push_back(new Caberet());
		m_PresetVector.push_back(new Fountains());
		m_PresetVector.push_back(new TwoMapSpiral());
		m_PresetVector.push_back(new Eyes());
		m_PresetVector.push_back(new Swirlpinski());
		m_PresetVector.push_back(new UnboundedAffine());
		m_PresetVector.push_back(new DravesGen165Sheep48());
		//m_PresetVector.push_back(new DravesGen165Sheep1099());
		//m_PresetVector.push_back(new DravesGen165Sheep19069());
		//m_PresetVector.push_back(new F9K1());
		//m_PresetVector.push_back(new JuliaCircle());
		//m_PresetVector.push_back(new Sierpinski());
	}

	static unsigned int Size() { return m_PresetVector.size(); }
	static Preset* Get(int index) { return m_PresetVector[index]; }

	~PresetList()
	{
		ClearPresets();
	}

private:
	static void ClearPresets()
	{
		for(unsigned int i = 0; i < m_PresetVector.size(); i++)
		{
			if (m_PresetVector[i] != NULL)
				delete m_PresetVector[i];

			m_PresetVector[i] = NULL;
		}

		m_PresetVector.clear();
	}

	static vector<Preset*> m_PresetVector;
};
}